-
-
Notifications
You must be signed in to change notification settings - Fork 554
[Bank account]: Add canonical data #2192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
"For this exercise it is possible to implement concurrency tests", | ||
"but for language tracks that do not support concurrency, the tests", | ||
"are written to be run in a single thread.", | ||
"But for language tracks that do support concurrency, so is it possible", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"is it possible" seems to imply a question, but the sentence here ends with a period instead of a question mark. Was it meant to be a question?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we talking about the sentence on line 7-8?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since line 4 has a pretty similar wording
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I improved it, can you check again?
} | ||
] | ||
}, | ||
"expected": { "error": "account not open" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fortunately, in all cases where this file has an "expected": { "error": "..." }
, it's always the case that it was the last operation that would cause the error.
If there were ever a case in the future where an operation other than the last one should cause the error, then putting it here would be unclear because it is unspecific about which operation should cause the error. In that case, it would be necessary to improve clarity by putting this "expected": { "error": "..." }
in the operation that should cause the error, instead of here.
I cannot predict at this time whether there will ever be such a case in the future, so I currently recommend that reviewers continue to consider this pull request in its current form ready to be Approved (in the GitHub sense of that word), rather than refusing to Approve it based on these grounds.
If we were to discover that there is likely a need for such cases in the future, I would recommend making the change now so that all these cases don't have to be reimplemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a good idea to make this convention clear though - the comments would say something like "if an error is expected, the last operation is the one that caused it; all operations other than the last one should succeed"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will see if other reviewers feels like there needs to be a structure change if not I will add that as a comment that it is the last one that should always be the action which will raise error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My 2 cents
"For this exercise it is possible to implement concurrency tests", | ||
"but for language tracks that do not support concurrency, the tests", | ||
"are written to be run in a single thread.", | ||
"But for language tracks that do support concurrency, it is possible", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This But
doesn't work because the previous case also has a but
. I suggest we change the entire thing to:
This exercise is a good candidate to practice concurrency, which
may not be available or possible in the implementing language track.
In this case, all tests can be executed on a single thread. If there
are tests that don't work using a single thread, these should be
marked with a concurrency scenario.
We probably also want to add concurrency
to https://github.com/exercism/problem-specifications/blob/main/SCENARIOS.txt.
}, | ||
{ | ||
"operation": "amount", | ||
"expected": 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're defining operations
to have an operand / function call name, and optional argument of value
, and an optional return expectation of expected
, I think we should move error
also into an operation expectation.
This also solves the potential ordering issue @petertseng mentions, and makes it easier to add interesting concurrency tests down the line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your feedback, do you think writing it like this makes sense?
{
"operation": "deposit",
"value": -50,
"error": "amount must be greater than 0"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps still nest it in expected
like before? @petertseng what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to prefer one over the other? Since I'm not currently aware of one, it seems we are empowered to make either choice. If a reason presents itself, then we would go with that one. For example, someone might say "all other error
are currently under expected
, and it is important for this to remain true because (they give a reason here)". You will notice that since I didn't have something to insert in the blank that I didn't put forth that reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since no one has written any test generator for this format yet, I agree, there is no reason from that point of view right now to pick one or the other.
@meatball133 I'll leave it up to you unless someone else comes up with a good reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would always add a comment for a future reader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless we're testing the behaviour of the system following an error
This type of test could be quite valuable if one of the desired teaching points of this exercise is to ensure that the system remains in a usable state after an erroneous operation. Ideally that decision wouldn't need to be made now, but I do regret to say that since it might have an effect on how some of these tests might need to be written, it seems it's necessary to at least plan for it. If there is no intent at all to have this as a teaching point, then all is well and we can end this particular thread of discussion here, and reading the rest of this comment is unnecessary.
But if error handling is one of the desired teaching points of this exercise, then just as an example, consider a test that opens an account, deposits a negative amount (which is not allowed), and then checks that the balance is still zero following that erroneous operation:
- Operations other than the last one could have an
expected
, with the outerexpected
still referring to the very last operation:
{
"uuid": "785f57e4-7c32-402e-a118-e3bfd4facf75",
"description": "Bad deposit doesn't corrupt balance",
"property": "bankAccount",
"input": {
"operations": [
{
"operation": "open"
},
{
"operation": "deposit",
"value": -50,
"expected": {"error": "amount must be greater than 0"}
},
{
"operation": "amount"
}
]
},
"expected": 0
}
- Or, each operation could have its own
expected
and the outer one remains empty.
{
"uuid": "785f57e4-7c32-402e-a118-e3bfd4facf75",
"description": "Bad deposit doesn't corrupt balance",
"property": "bankAccount",
"input": {
"operations": [
{
"operation": "open"
},
{
"operation": "deposit",
"value": -50,
"expected": {"error": "amount must be greater than 0"}
},
{
"operation": "amount"
"expected": 0
}
]
},
"expected": {}
}
I have no reason to prefer one or the other, but if someone does, it would be good to mention the reason for that preference right now.
I also wouldn't consider having such tests a necessary condition to have this pull request be Approved (in the GitHub sense of the word), but I'll phrase it as: It wouldn't be surprising to see an additional pull request from me some time after this pull request is merged if this is indeed a desired teaching point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hear what you're saying about the teaching point.
Of these options, I prefer # 1. That indicates that we want to produce that result from the entire sequence of operations. Contrast to # 2 where the actual expected result of the test case is ambiguous.
I think we'd want to give some hint to track implementors that in this situation, the erroring operation has a non-fatal error or the error is to be trapped. Perhaps we could add
- a (new) scenario to the case or
- a
"fatal": false
property to theexpected
object of the middle operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for taking a while, I will replay later today. Promise, aslong as I dont get a power outage but that usually doesnt happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I have read through the feedback. I think we can go with method one. But there are no current test cases which has any other operations in the middle so the fatal flag doesn't need to be applied anywhere. Unless you guys come up with some new tests. But I can convert the tests to suggestion 1. I can also write a comment about how we think about this design.
Co-authored-by: Glenn Jackman <[email protected]>
9bf3f03
to
16c6f5b
Compare
This reverts commit 16c6f5b.
I'm satisfied with the current canonical data. @petertseng @SleeplessByte where do you stand now? |
Co-authored-by: Peter Tseng <[email protected]>
Please amend the commit message to include the string " |
Co-authored-by: Peter Tseng <[email protected]>
I added so this pr will close that issue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this!
}, | ||
{ | ||
"uuid": "ec42245f-9361-4341-8231-a22e8d19c52f", | ||
"description": "Cannot withdraw more than deposited", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
}, | ||
{ | ||
"uuid": "0722d404-6116-4f92-ba3b-da7f88f1669c", | ||
"description": "Reopened account does not retain balance", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a new test case AFAICT, correct? This test case and a0a1835d-faae-4ad4-a6f3-1fcc2121380b are the two test cases of which I'm not sure about. Most existing implementations of this exercise don't have these check I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python has both of those tests, I can't speak although for how other tracks have done it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's one implementation that I didn't do. Let's keep them then.
Co-authored-by: Erik Schierboom <[email protected]>
@ErikSchierboom did you intend it like this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two nits, and then we should be good to go!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found just one tiny nit (sorry)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's gooooo
@glennj please have a final look :) |
"concurrent_operations": [ | ||
{ | ||
"operation": "deposit", | ||
"amount": 1 | ||
}, | ||
{ | ||
"operation": "withdraw", | ||
"amount": 1 | ||
} | ||
], | ||
"operations": [ | ||
{ | ||
"operation": "balance" | ||
} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is the open
operation for this account?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @meatball133
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petertseng can you have a look here please
Awsome! Co-authored-by: Glenn Jackman <[email protected]>
"scenarios": ["concurrent"], | ||
"property": "bankAccount", | ||
"input": { | ||
"initial_operations": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the consensus is that this is the best way to do things then I won't stand in your way. It strikes me as:
- inflexible (since now you can only have concurrent operations in between an initial and final section, instead of arbitrary interleavings)
- violating the schema (the same
property
,"bankAccount"
, now may haveinput
of different types: it might either haveoperations
, or not, violating the rule that the sameproperty
hasinput
of the same type.)
What I expected to see was:
{
"input": {
"operations": [
{
"operation": "open"
},
{
"operation": "concurrent",
"number": 1000,
"operations": [
{
"operation": "deposit",
"amount": 1
},
{
"operation": "withdraw",
"amount": 1
}
]
},
{
"operation": "balance"
},
]
},
"expected": 0
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer this too. This also allows us to have multiple batches of concurrent operations instead of always serial start concurrent serial end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@glennj and @ErikSchierboom, I think we should have a solution we all agree upon so I want to hear your thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on board with this suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Me too. That sounds like a better approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remember to properly edit the commit message when merging. We do not want to be discourteous to our future selves and future contributors by including a commit message with a bunch of lines that just say "fixed" and "updated"
Thanks @meatball133! |
The goal with this pr is to bring so a higher percentage of the practice exercises has tests and also to make it easier for new tracks to implement the exercise.
Some tracks have taken the decision to add a concurrency test, I was a bit unsure how to implement it in the canonical-data.json since it needs for loops for a lot of tracks. And some tracks doesn't it make sense to test for concurrency.
Any way feedback appreciated
resolves: #554